﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MugenInjection;
using MugenInjection.Interface;
using MugenInjection.Parameters;
using TestModels.Class;
using TestModels.Interface;

namespace MugenInjectionTest.Core
{
    [TestClass]
    public partial class InjectorResolverTest : TestBase
    {
        [TestMethod]
        public void TestCreateContext()
        {
            using (MugenInjector injector = GetInjector())
            {
                var parameters = new IInjectionParameter[0];
                var dict = new Dictionary<string, object>();
                IBindingContext bindingContext = injector.CreateContext(ServiceType, TypeInto, ParameterInfo,
                                                                              parameters, dict);
                Assert.AreEqual(bindingContext.Injector, injector);
                Assert.AreEqual(bindingContext.CallInjector, injector);
                Assert.AreEqual(bindingContext.Service, ServiceType);
                Assert.AreEqual(bindingContext.TypeInto, TypeInto);
                Assert.AreEqual(bindingContext.Member, TypeInto);
                Assert.AreEqual(bindingContext.ParameterInfo, ParameterInfo);
                Assert.AreEqual(bindingContext.Parameters, parameters);
                Assert.AreEqual(bindingContext.SpecialParameters, dict);
                TestUtils.Catch<ArgumentNullException>(() => injector.CreateContext(null, null, null, null, null));
            }
        }

        [TestMethod]
        public void TestCanResolveCorrectContext()
        {
            var dictionary = new Dictionary<string, object>() { { "1", "1" } };
            IInjectionParameter parameter = new PropertyParameter("es", typeof(object), null);

            //Simple
            using (var parent = GetInjector())
            {
                parent.Bind<ISimple>().To<Simple>();
                Assert.IsTrue(parent.CanResolve(typeof(ISimple)));
            }

            //Simple with parameters
            using (var parent = GetInjector())
            {
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter));
                Assert.IsTrue(parent.CanResolve(typeof(ISimple), true, false, null, parameter));
                Assert.IsFalse(parent.CanResolve(typeof(ISimple)));
            }

            //Simple with parent
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>();
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), true));
            }

            //Simple with parent and parameter
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, false, null, parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false));

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), true, false, null, parameter));
            }

            //Simple self bindable
            using (var parent = GetInjector())
            {
                Assert.IsTrue(parent.CanResolve(typeof(Simple), true, true));
                Assert.IsTrue(parent.CanResolve(typeof(Simple), false, true));
                Assert.IsFalse(parent.CanResolve(typeof(Simple), false, false));
            }

            //Simple with parent and parameter and self bindable flag
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, true, null, parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, true));

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, true));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), true, true, null, parameter));
            }

            //Simple with special parameters and parameters
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.SpecialParameters.ContainsKey("1") && binding.Parameters.Contains(parameter));

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, true, dictionary));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, false, dictionary));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), true, false, dictionary));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), true, true, dictionary));

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, true, dictionary, parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), false, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), true, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), true, true, dictionary, parameter));
            }

            //Simple named and parameter
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter)).NamedBinding("name");

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, true));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, false));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", true, false));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", true, true));

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, true, null, parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, false, null, parameter));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), "name", true, false, null, parameter));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), "name", true, true, null, parameter));
            }

            //Simple named and parameter with special parameters
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>()
                    .When(binding => binding.Parameters.Contains(parameter) && binding.SpecialParameters.ContainsKey("1"))
                    .NamedBinding("name");

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, true, dictionary));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, false, dictionary));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", true, false, dictionary));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", true, true, dictionary));

                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, true, dictionary, parameter));
                Assert.IsFalse(injector.CanResolve(typeof(ISimple), "name", false, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), "name", true, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolve(typeof(ISimple), "name", true, true, dictionary, parameter));
            }
        }

        [TestMethod]
        public void TestCanResolveCorrectContextInto()
        {
            var dictionary = new Dictionary<string, object>() { { "1", "1" } };
            IInjectionParameter parameter = new PropertyParameter("es", typeof(object), null);
#if NETFX_CORE
            TypeInfo typeInto = typeof(Attribute).GetTypeInfo();
#else
            Type typeInto = typeof(Attribute);
#endif


            //Simple
            using (var parent = GetInjector())
            {
                parent.Bind<ISimple>().To<Simple>().WhenInto(typeInto.AsType());
                Assert.IsTrue(parent.CanResolveInto(typeof(ISimple), typeInto));
            }

            //Simple with parameters
            using (var parent = GetInjector())
            {
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter) && binding.TypeInto == typeInto.AsType());
                Assert.IsTrue(parent.CanResolveInto(typeof(ISimple), typeInto, null, true, false, null, parameter));
                Assert.IsFalse(parent.CanResolveInto(typeof(ISimple), typeInto));
            }

            //Simple with parent
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().WhenInto(typeInto.AsType());
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), typeInto, null, true));
            }

            //Simple with parent and parameter
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter) && binding.TypeInto == typeInto.AsType());
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, false, null, parameter));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, false, null));

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, false, null));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), typeInto, null, true, false, null, parameter));
            }

            //Simple self bindable
            using (var parent = GetInjector())
            {
                Assert.IsTrue(parent.CanResolveInto(typeof(Simple), typeInto, null, true, true));
                Assert.IsTrue(parent.CanResolveInto(typeof(Simple), typeInto, null, false, true));
                Assert.IsFalse(parent.CanResolveInto(typeof(Simple), typeInto, null, false, false));
            }

            //Simple with parent and parameter and self bindable flag
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>().When(binding => binding.Parameters.Contains(parameter) && binding.TypeInto == typeInto.AsType());
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, true, null, parameter));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, true));

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, true));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), typeInto, null, true, true, null, parameter));
            }

            //Simple with special parameters and parameters
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>()
                    .When(binding => binding.SpecialParameters.ContainsKey("1") && binding.Parameters.Contains(parameter) && binding.TypeInto == typeInto.AsType());

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, true, dictionary));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, false, dictionary));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, true, false, dictionary));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, true, true, dictionary));

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, true, dictionary, parameter));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), typeInto, null, false, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), typeInto, null, true, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), typeInto, null, true, true, dictionary, parameter));
            }

            //Simple named and parameter
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>()
                    .When(binding => binding.Parameters.Contains(parameter) && binding.TypeInto == typeInto.AsType()).NamedBinding("name");

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, true));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, false));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, false));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, true));

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, true, null, parameter));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, false, null, parameter));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, false, null, parameter));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, true, null, parameter));
            }

            //Simple named and parameter with special parameters
            using (var parent = GetInjector())
            {
                var injector = (MugenInjector)parent.CreateChild();
                parent.Bind<ISimple>().To<Simple>()
                    .When(binding => binding.Parameters.Contains(parameter) && binding.SpecialParameters.ContainsKey("1") && binding.TypeInto == typeInto.AsType())
                    .NamedBinding("name");

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, true, dictionary));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, false, dictionary));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, false, dictionary));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, true, dictionary));

                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, true, dictionary, parameter));
                Assert.IsFalse(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, false, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, false, dictionary, parameter));
                Assert.IsTrue(injector.CanResolveInto(typeof(ISimple), "name", typeInto, null, true, true, dictionary, parameter));
            }
        }

        public class Test1
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="T:System.Object"/> class.
            /// </summary>
            public Test1(string st)
            {
            }
        }

        public class Test2
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="T:System.Object"/> class.
            /// </summary>
            public Test2(string st)
            {
            }
        }

        [TestMethod]
        public void TestGetGeneric()
        {
            var mugenInjector = GetInjector();
            mugenInjector.Bind<string>().ToConstant("test").WhenInto<Test1>();
            mugenInjector.Bind<string>().ToConstant("test2").WhenInto<Test2>();

            mugenInjector.Get<Test1>();
            mugenInjector.Get<Test2>();

            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters);
                Assert.AreEqual(injector.Get<string>(parameters), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict);
                Assert.AreEqual(injector.Get<string>(dict), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters);
                Assert.AreEqual(injector.Get<string>(dict, parameters), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name, dict), value);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name, dict, parameters), value);
            }
        }

        [TestMethod]
        public void TestGetIntoGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, null, parameters), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, dict), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, dict, parameters), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo, dict), value);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo, dict, parameters), value);
            }
        }

        [TestMethod]
        public void TestGetNonGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            var bindType = typeof(string);

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters);
                Assert.AreEqual(injector.Get(bindType, parameters), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict);
                Assert.AreEqual(injector.Get(bindType, dict), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters);
                Assert.AreEqual(injector.Get(bindType, dict, parameters), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get(bindType, name), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get(bindType, name, dict), value);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get(bindType, name, dict, parameters), value);
            }
        }

        [TestMethod]
        public void TestGetIntoNonGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            var bindType = typeof(string);

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto(bindType, TypeInto, ParameterInfo, null, parameters), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto(bindType, TypeInto, ParameterInfo, dict), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto(bindType, TypeInto, ParameterInfo, dict, parameters), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto(bindType, name, TypeInto, ParameterInfo), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto(bindType, name, TypeInto, ParameterInfo, dict), value);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto(bindType, name, TypeInto, ParameterInfo, dict, parameters), value);
            }
        }

        [TestMethod]
        public void TestTryGetGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters);
                Assert.IsTrue(injector.TryGet(out getValue, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict);
                Assert.IsTrue(injector.TryGet(out getValue, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters);
                Assert.IsTrue(injector.TryGet(out getValue, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGet(out getValue, name));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGet(out getValue, name, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGet(out getValue, name, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
        }

        [TestMethod]
        public void TestTryGetNonGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            var bindType = typeof(string);

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters);
                Assert.IsTrue(injector.TryGet(bindType, out getValue, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict);
                Assert.IsTrue(injector.TryGet(bindType, out getValue, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters);
                Assert.IsTrue(injector.TryGet(bindType, out getValue, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGet(bindType, out getValue, name));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGet(bindType, out getValue, name, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGet(bindType, out getValue, name, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
        }

        [TestMethod]
        public void TestTryGetIntoGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.IsTrue(injector.TryGetInto(out getValue, TypeInto, ParameterInfo, null, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.IsTrue(injector.TryGetInto(out getValue, TypeInto, ParameterInfo, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.IsTrue(injector.TryGetInto(out getValue, TypeInto, ParameterInfo, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGetInto(out getValue, name, TypeInto, ParameterInfo));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGetInto(out getValue, name, TypeInto, ParameterInfo, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                string getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGetInto(out getValue, name, TypeInto, ParameterInfo, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
        }

        [TestMethod]
        public void TestTryGetIntoNonGeneric()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            var bindType = typeof(string);

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.IsTrue(injector.TryGetInto(bindType, out getValue, TypeInto, ParameterInfo, null, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.IsTrue(injector.TryGetInto(bindType, out getValue, TypeInto, ParameterInfo, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.IsTrue(injector.TryGetInto(bindType, out getValue, TypeInto, ParameterInfo, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGetInto(bindType, out getValue, name, TypeInto, ParameterInfo));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGetInto(bindType, out getValue, name, TypeInto, ParameterInfo, dict));
                Assert.AreEqual(value, getValue);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                object getValue;
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters && context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.IsTrue(injector.TryGetInto(bindType, out getValue, name, TypeInto, ParameterInfo, dict, parameters));
                Assert.AreEqual(value, getValue);
            }
        }

/*#if !NOEXPRESSION
        [TestMethod]
        public void TestGetExpression()
        {
            var parameters = new IInjectionParameter[] {new ConstructorParameter("Test", "test")};
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.Parameters[0] == parameters[0]);
                Assert.AreEqual(injector.Get(context => new string(context.Resolve<char[]>()), parameters), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>().ToConstant(value).When(context => context.SpecialParameters == dict);
                Assert.AreEqual(injector.Get(context => new string(context.Resolve<char[]>()), dict), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters[0] == parameters[0]);
                Assert.AreEqual(injector.Get(context => new string(context.Resolve<char[]>()), dict, parameters), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get(context => new string(context.Resolve<char[]>()), name), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get(context => new string(context.Resolve<char[]>()), name, dict), value);
            }
            //Only named binding and special parameters and parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty);
                injector.Bind<string>()
                    .ToConstant(value)
                    .When(context => context.SpecialParameters == dict && context.Parameters[0] == parameters[0])
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get(context => new string(context.Resolve<char[]>()), name, dict, parameters), value);
            }
        }
#endif*/

    }
}
